package com.kt.common

import com.kt.common.`fun`.*
import com.kt.common.`fun`.DerivedCaller
import javax.swing.tree.TreeNode


fun main() {


    //函数定义的最后一个方法是一个lambda表达式，可使用下边方式
    /*foo(qux = fun(){
        println("普通实现")
    })*/
    //也可以用以下方式
    /*foo {
        print("使用lambda表达式方式")
    }*/

    //foo1("1", "2")

    //高阶函数
    //使用匿名函数的方式定义
    //val items = listOf<Int>(1, 2, 3, 4, 5, 6, 7)
    //items.fold(0,aaa)
    /*items.fold("2",fun(a:String,b:Int):String{
        println("result=${a}+${b}")
        return "$a + $b"
    })*/
    //使用lambda表达式来实现
    /*items.fold(2) { a: Int, b: Int ->
        println("a+b = $a + $b = ${a + b}")
        a + b
    }*/
    //根据前面的类型可自动推断出来类型
    /*items.fold("joy"){
        a,c->
        println("a+c=${a}+${c}")
        a+c
    }*/


    // 函数引用也可以用于高阶函数调用：
    /*val product = items.fold(1, Int::plus)
    println(product)
    println(List<Int>::toString)*/


    //println({ a: Int, b: Int -> a + b })
    /*val gJ01 = GJ01(10, 20) { a, b ->
        a + b
    }
    println(gJ01)
    val a = { i: Int -> i + 1 }
    println(a)*/

    //此处如果能推断出来类型，  可使用挂起函数
    /*val repeatFun: String.(String) -> String = { it -> this.replace("o",it) }
    val twoParameters: (String, String) -> String = repeatFun // OK

    fun runTransformation(f: (String, String) -> String): String {
        return f("hello", "world")
    }
    val result = runTransformation(repeatFun) // OK
    println(result)*/

    //使用挂起函数对String ，Int 的扩展
    /*val stringPlus: String.(String) -> String = String::plus
    val intPlus: Int.(Int) -> Int = Int::plus

    println(stringPlus("<---", "--->"))
    println("hello".stringPlus("\tworld"))

    println(intPlus(1, 2))
    println(3.intPlus(1))*/

    //两种使用方法函数方法
    /*val count1 = 3 sumInfix 5 + 4
    println(count1)
    println(3.sumInfix(6))*/

    //访问类中的成员函数
    //Sample().foo()

    //泛型函数
    /*val singleList = singleList<Int>(90, 80, 7)
    singleList.forEach {
        println(it)
    }*/

    /*val listOf = listOf(1, 2, 3, 4, 5, 6)

    println(sumOf(3, listOf))*/

    /*val mList = mutableListOf<Int>(1, 2, 3, 4, 5, 6)
    mList.swap(3, 5)
    mList.printList()*/

    /*Example().printFunctionType()
    Example().printFunctionType(2)*/
    /*var a :Any = ""
    println(a.toString())*/

    /*val mList = mutableListOf<Int>(1, 2, 3, 4, 5, 6)
    println(mList.lastIndex)*/

    /* val sample = Sample()
     sample.count = -1
     println(sample.count)*/
    /*val sample = Sample()
    //println(sample.name)
    sample.name = "张三"
    println(sample.name)*/
    //Sample.printCompanion()

    //Connection
    /*val connection = Connection(Host("https://www.baidu.com"), 443)
    connection.connect()
    //此处在类里边定义的扩展函数只能在内部调用不能在外部调用
    Host("https://www.baidu.com").printConnectionToString()*/


    /**** 声明为成员的扩展可以声明为 open 并在子类中覆盖。
     * 这意味着这些函数的分发对于分发接收者类型是虚拟的，但对于扩展接收者类型是静态的。*/
    //在没加call(base:Derived)重载的时候
    BaseCaller().call(Base())   // “Base extension function in BaseCaller”
    DerivedCaller().call(Base())  // “Base extension function in DerivedCaller”——分发接收者虚拟解析
    DerivedCaller().call(Derived())  // “Base extension function in DerivedCaller”——扩展接收者
    //加了重载的时候
    //Base extension function in BaseCaller
    //Base extension function in DerivedCaller
    //Derived extension function in DerivedCaller

    //表达式中解构 Map.Entry<K, V>) -> R  参考es6中的解构函数
    /*val hashMap = HashMap<String, String>()
    hashMap.mapValues {
        (key,va) ->
    }*/

//    val a = 1_000_000

}

fun GJ01(initial1: Int, initial2: Int, funSum: (a: Int, b: Int) -> Int): Int {
    return funSum(initial1, initial2)
}

//使用匿名函数的方式
val aaa = fun(a: Int, b: Int): Int {
    println("a+b = $a + $b = ${a + b}")
    return a + b
}

/**函数定义方式*/
/**基础函数定义方式*/
/*
fun sum(a: Int, b: Int) {
    print("a=${a} + b= $b ,a+b=${a+b}")
}*/

//fun sum(a: Int, b: Int) :Unit=  print("a=${a} + b= $b ,a+b=${a+b}")

// 此特性函数不需要写重载函数了，直接用默认函数来实现sum(a=2,b=1)---具名函数 这样调用
/*fun sum(
    a:Int = 0,
    b:Int = 6
){
    println()
    print("a=${a} + b= $b ,a+b=${a+b}")
}*/

// 定义的函数方法中有函数
fun foo(
    bar: Int = 0,
    baz: Int = 1,
    qux: () -> Unit
) {
    println("bar=${bar}")
    println("baz=${baz}")
    println(qux)
    qux()
}

//可变参数
fun foo1(vararg strs: String) {
    strs.forEach {
        println(it)
    }
}

//中缀函数--用于扩展Int的函数
infix fun Int.sumInfix(a: Int): Int {
    return this + a
}


/**高阶函数： 高阶函数是将函数用作参数或返回值的函数*/
// eg. 它接受一个初始累积值与一个接合函数，并通过将当前累积值与每个集合元素连续接合起来代入累积值来构建返回值
fun <T, R> Collection<T>.fold(
    initial: R,
    combine: (R, T) -> R
): R {
    var accumulator: R = initial
    for (element in this) {
        accumulator = combine(accumulator, element)
    }
    return accumulator
}

//使用lambda表达式来表示函数表达式
val funA = { }

//此处存在函数作用域
fun dfs(graph: Int) {
    val visited = HashSet<Int>()
    fun dfs(current: Int) {
        //此处可以使用外部函数的局部变量 （闭包）
        if (visited.contains(current)) return
        else visited.add(current)
    }

    dfs(graph)
}

//泛型函数
fun <E> singleList(vararg item: E): MutableList<E> {
    val list = mutableListOf<E>()
    for (it in item) {
        list.add(it)
    }
    return list
}

var sumOfStr: String = "0"

//尾递归函数 --- 当一个函数用 tailrec 修饰符标记并满足所需的形式时，编译器会优化该递归，留下一个快速而高效的基于循环的版本
tailrec fun sumOf(index: Int, list: List<Int>): Int =
    if (index >= list::size.get()) 0 else list[index] + sumOf(index + 1, list)

/**扩展函数*/
fun MutableList<Int>.swap(a: Int, b: Int) {
    val temp = this[a]
    this[a] = this[b]
    this[b] = temp
}

fun MutableList<Int>.printList() {
    this.forEach {
        print(it)
    }
}


//Example().printFunctionType() 会调用Example类的函数，而不会调用扩展函数的方法，这样保证类函数的安全性
//当然，扩展函数重载同样名字但不同签名成员函数也完全可以
class Example {
    fun printFunctionType() {
        println("Class method")
    }
}

fun Example.printFunctionType() {
    println("Extension function")
}

//函数重载
fun Example.printFunctionType(i: Int) {
    println("Extension function $i")
}

//扩展函数可空
fun Any?.toString(): String {
    if (this == null) return "null"
    // 空检测之后，“this”会自动转换为非空类型，所以下面的 toString()
    // 解析为 Any 类的成员函数
    return toString()
}

//扩展属性

val <E>List<E>.lastIndex: Int
    get() = size - 1

//伴生对象的扩展属性
fun Sample.Companion.printCompanion() {
    println("companion")
}

/**具体化的类型参数*/
fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
    var p = parent
    while (p!=null && !clazz.isInstance(p)) {
        p = p.parent
    }
    return p as T
}


//使用reified 修饰符来限定T的类型，在函数内部is as 都可以可以直接访问它了，不使用只有部分可以使用
inline fun <reified T> TreeNode.findParentOfType(): T? {
    var p = parent
    while (p != null && p !is T) {
        p = p.parent
    }
    return p as T?
}

inline fun <reified T> membersOf() = T::class.members


//内联属性 ---》可以标注独立的属性访问器，也可以标注整个属性
/*
val foo: Foo
    inline get() = Foo()

var bar: Bar
    get()
inline set(v) { …… }
inline var bar: Bar
    get() = ……
    set(v) { …… }
*/
